package com.stanyung.realtimeclient.io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

import com.stanyung.realtimeclient.Packet;
import com.stanyung.realtimeclient.common.ByteUtil;
import com.stanyung.realtimeclient.common.Constants;

public class PacketReceiveHandler implements DataReceiveHandler {

	private int needing = 0;
	private byte[] data;
	private int lenReaded = 0;
	private byte[] lenData = new byte[4];
	private PacketLogicQueue packetLogicQueue;

	public PacketReceiveHandler() {
		packetLogicQueue = new PacketLogicQueue();
	}

	@Override
	public void onReceived(byte[] data) throws IOException {
		System.out.println("onReceived :: " + Arrays.toString(data));
		ByteArrayInputStream in = new ByteArrayInputStream(data);
		readRemaining(in, data.length);
	}

	private void readRemaining(InputStream in, int remaining)
			throws IOException {

		byte[] buff;
		if (needing == 0) { // New Packet
			if (lenReaded > 0) {
				int readCount = in.read(lenData, lenReaded, 4 - lenReaded);
				needing = ByteUtil.bytes2Int(lenData);
				data = new byte[needing];
				lenReaded = 0;
				remaining -= readCount;
				readRemaining(in, remaining);
			} else if (remaining >= 4) {
				buff = new byte[4];
				in.read(buff);
				needing = ByteUtil.bytes2Int(buff);
				data = new byte[needing];
				remaining -= 4;
				if (remaining > 0) {
					readRemaining(in, remaining);
				}
			} else {
				lenData = new byte[4];
				in.read(lenData, 0, remaining);
				lenReaded = remaining;
			}
		} else {
			lenReaded = 0;
			int len = Math.min(needing, remaining);
			buff = new byte[len];
			in.read(buff);
			System.arraycopy(buff, 0, data, data.length - needing, len);
			needing -= len;
			remaining -= len;
			if (needing == 0) {
				if(data.length >= Constants.HEAD_LENGTH) {
					Packet packet = Packet.parse(data);
					packetLogicQueue.handlePacket(packet);
				}
				data = null;
			}
			if (remaining > 0) {
				readRemaining(in, remaining);
			}
		}
	}

}
